{%   from 'macros.common.j2' import apply_alphabetical_ordering_by_brk_descriptions
%}{% from 'macros.common.j2' import apply_alphabetical_ordering_by_descriptions
%}{% from 'macros.common.j2' import apply_alphabetical_ordering_by_release_notices
%}{% from 'macros.common.j2' import emoji_map, format_breaking_changes_description
%}{% from 'macros.common.j2' import format_release_notice, section_heading_order
%}{% from 'macros.common.j2' import section_heading_translations
%}{% from 'macros.rst.j2' import extract_issue_link_references, extract_pr_link_reference
%}{% from 'macros.rst.j2' import format_commit_summary_line, format_link_reference
%}{% from 'macros.rst.j2' import generate_heading_underline
%}{#

✨ Features
-----------

* Add new feature (`#10`_, `8a7b8ec`_)

* **scope**: Add another feature (`abcdef0`_)

🪲 Bug Fixes
------------

* Fix bug (`#11`_, `8a7b8ec`_)

💥 Breaking Changes
-------------------

* With the change _____, the change causes ___ effect. Ultimately, this section
  it is a more detailed description of the breaking change. With an optional
  scope prefix like the commit messages above.

* **scope**: this breaking change has a scope to identify the part of the code that
  this breaking change applies to for better context.

💡 Additional Release Information
---------------------------------

* This is a release note that provides additional information about the release
  that is not a breaking change or a feature/bug fix.

* **scope**: this release note has a scope to identify the part of the code that
  this release note applies to for better context.

.. _8a7B8ec: https://domain.com/owner/repo/commit/8a7b8ec
.. _abcdef0: https://domain.com/owner/repo/commit/abcdef0
.. _PR#10: https://domain.com/namespace/repo/pull/10
.. _PR#11: https://domain.com/namespace/repo/pull/11

#}{%  set max_line_width = max_line_width | default(100)
%}{%  set hanging_indent = hanging_indent | default(2)
%}{#
#}{%  set post_paragraph_links = []
%}{#
#}{%  for type_ in section_heading_order if type_ in commit_objects
%}{#    # PREPARE SECTION HEADER
#}{%    set section_header = "%s %s" | format(
          emoji_map[type_], type_ | title
        )
%}{#
   #    # PREPROCESS COMMITS
#}{%    set ns = namespace(commits=commit_objects[type_])
%}{%    set _ = apply_alphabetical_ordering_by_descriptions(ns)
%}{#
#}{%    set commit_descriptions = []
%}{#
#}{%    for commit in ns.commits
%}{#      # Extract PR/MR reference if it exists and store it for later
#}{%      set pr_link_reference = extract_pr_link_reference(commit) | default("", true)
%}{%      if pr_link_reference != ""
%}{%        set _ = post_paragraph_links.append(pr_link_reference)
%}{%      endif
%}{#
   #      # Extract Issue references if they exists and store it for later
#}{%      set issue_urls_ns = namespace(urls=[])
%}{%      set _ = extract_issue_link_references(issue_urls_ns, commit)
%}{%      set _ = post_paragraph_links.extend(issue_urls_ns.urls)
%}{#
   #      # Always generate a commit hash reference link and store it for later
#}{%      set commit_hash_link_reference = format_link_reference(
            commit.hexsha | commit_hash_url,
            commit.short_hash
          )
%}{%      set _ = post_paragraph_links.append(commit_hash_link_reference)
%}{#
   #      # Generate the commit summary line and format it for RST
#}{%      set description = "* %s" | format(format_commit_summary_line(commit))
%}{%      set description = description | convert_md_to_rst
%}{%      set description = description | autofit_text_width(max_line_width, hanging_indent)
%}{%      set _ = commit_descriptions.append(description)
%}{%    endfor
%}{#
   #    # PRINT SECTION (Header & Commits)
   #    Note: Must add an additional character to the section header when determining the underline because of
   #    the emoji character which can serve as 2 characters in length.
#}{{    "\n"
}}{{    section_header ~ "\n"
}}{{    generate_heading_underline(section_header ~ " ", '-') ~ "\n"
}}{{
        "\n%s\n" | format(commit_descriptions | unique | join("\n\n"))

}}{%  endfor
%}{#
   #  # Determine if any commits have a breaking change or release notice
   #  # commit_objects is a dictionary of strings to a list of commits { "features", [ParsedCommit(), ...] }
#}{%  set breaking_commits = []
%}{%  set notice_commits = []
%}{%  for commits in commit_objects.values()
%}{%    set valid_commits = commits | rejectattr("error", "defined") | list
%}{#    # Filter out breaking change commits that have no breaking descriptions
#}{%    set _ = breaking_commits.extend(
          valid_commits | selectattr("breaking_descriptions.0")
        )
%}{#    # Filter out ParsedCommits commits that have no release notices
#}{%    set _ = notice_commits.extend(
          valid_commits | selectattr("release_notices.0")
        )
%}{%  endfor
%}{#
#}{%  if breaking_commits | length > 0
%}{#    # PREPROCESS COMMITS
#}{%    set brk_ns = namespace(commits=breaking_commits)
%}{%    set _ = apply_alphabetical_ordering_by_brk_descriptions(brk_ns)
%}{#
#}{%    set brking_descriptions = []
%}{#
#}{%    for commit in brk_ns.commits
%}{%      set full_description = "* %s" | format(
            format_breaking_changes_description(commit).split("\n\n") | join("\n\n* ")
          )
%}{%      set _ = brking_descriptions.append(
            full_description | convert_md_to_rst | autofit_text_width(max_line_width, hanging_indent)
          )
%}{%    endfor
%}{#
   #    # PRINT BREAKING CHANGE DESCRIPTIONS (header & descriptions)
#}{{    "\n"
}}{{    "%s Breaking Changes\n" | format(emoji_map["breaking"])
}}{{    '-------------------\n'
}}{{
        "\n%s\n" | format(brking_descriptions | unique | join("\n\n"))
}}{#
#}{%  endif
%}{#
#}{%  if notice_commits | length > 0
%}{#    PREPROCESS COMMITS
#}{%    set notice_ns = namespace(commits=notice_commits)
%}{%    set _ = apply_alphabetical_ordering_by_release_notices(notice_ns)
%}{#
#}{%    set release_notices = []
%}{#
#}{%    for commit in notice_ns.commits
%}{%      set full_description = "* %s" | format(
            format_release_notice(commit).split("\n\n") | join("\n\n* ")
          )
%}{%      set _ = release_notices.append(
            full_description | convert_md_to_rst | autofit_text_width(max_line_width, hanging_indent)
          )
%}{%    endfor
%}{#
   #    # PRINT RELEASE NOTICE INFORMATION (header & descriptions)
#}{{    "\n"
}}{{    "%s Additional Release Information\n" | format(emoji_map["release_note"])
}}{{    "---------------------------------\n"
}}{{
        "\n%s\n" | format(release_notices | unique | join("\n\n"))
}}{#
#}{%  endif
%}{#
   #
   #  # PRINT POST PARAGRAPH LINKS
#}{%  if post_paragraph_links | length > 0
%}{#    # Print out any PR/MR or Issue URL references that were found in the commit messages
#}{{    "\n%s\n" | format(post_paragraph_links | unique | sort | join("\n"))
}}{%  endif
%}
